#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <string>
#include <iostream>
#include <QtCore>
#include <QCoreApplication>
#include <QDebug>

#include "pocker.h"
#include "../Common/Player.h"
#include "InferenceEngine.h"
#include "../Common/GameInfo.h"
#include "../Common/PokerTool.h"

using namespace std;

string strategy;

size_t traitement_client(int sockfd,string nom)
{
	cout << "traitement client" << std::endl;
	char recvline[1000];
	for(int i=0;i<1000;i++)
		recvline[i] = '\0';

	string rece;
	string response = "";

	// Attente et Lecture du message retour /
	if(read(sockfd, recvline, 1000) != 0)
	{
		rece.append(recvline);
	}

	cout << "message recu" << "("<< nom <<")" <<" du serveur : " << rece << endl;

	GameInfo gameinfo;

	if(USE_COMMUNICATION_XML)
	{
		//DataNetworkRepresentation::decoding(rece.c_str(), gameinfo);
	}
	else
	{
		grammaire(rece,gameinfo,gameinfo.getPlayer(1));
		gameinfo.setCurrentPlayer(1);
	}
	qDebug() << "Current player: " << QString::number(gameinfo.getCurrentPlayer());
	qDebug() << "strategy : " << gameinfo.getPlayers()[gameinfo.getCurrentPlayer()].getStrategy();
	cout << "gameinfo.getPlayer(1)" << gameinfo.getPlayer(1).toString(
			gameinfo.getPlayer(2).getBetInt(),
			gameinfo.getGameState(),
			gameinfo.getPlayer(1).getBetInt(),
			gameinfo.getwinner()
			)<< endl;
	cout << "gameinfo.getPlayer(2)" << gameinfo.getPlayer(2).toString(
			gameinfo.getPlayer(1).getBetInt(),
			gameinfo.getGameState(),
			gameinfo.getPlayer(1).getBetInt(),
			gameinfo.getwinner()
			)<< endl;
	/**
	 * Alors c'est pas forcement l'idéal, mais ca fonctionne :
	 *
	 *  - Le joueur : gameinfo.getPlayer(1) est toujours le joueur courant
	 *
	 *   - Le joueur : gameinfo.getPlayer(2) est toujours l'autre joueur
	 *   (La seul information du joueur 2 qui est setter est la variable bet,
	 *   pour y accéder, via un entier, il faut utiliser : int getBetInt() )
	 *
	 * 	- Actuellment la position est défini en 9 et 10, si ca te vas pas,
	 * 	  ca peut me prendre 30s. à le modifier
	 */
	//Fonction random
	if( USE_DECISION_RANDOM )
	{
		cout << "Utilisation de la stratégie random par défault "<< endl;
		gameinfo.getPlayers()[1].randomDecision(gameinfo.getPlayer(1));
	}
	else
	{
		//Si etat de fin de partie
		if(gameinfo.getGameState() == 4)
		{
			cout << "---------- Recu message de fin de partie------------------" << endl;
			if(USE_LEARNING_END_GAME)
			{
				// Inference engine
				InferenceEngine inferenceEngine(gameinfo);
				gameinfo = inferenceEngine.LaunchInferenceEngine();
			}
			else
				response="OK";
		}
		else if(gameinfo.getPlayers()[1].getStrategy() == "random" || gameinfo.getGameState() != 0)
		{
			cout << "Utilisation de la stratégie random "<< endl;
			gameinfo.getPlayers()[1].randomDecision(gameinfo.getPlayer(1));
		}
		else
		{
			cout << "Utilisation du moteur d'inférence "<< endl;
			// Inference engine
			InferenceEngine inferenceEngine(gameinfo);
			gameinfo = inferenceEngine.LaunchInferenceEngine();
			cout << ":::" << gameinfo.getPlayer(1).getAction().toStdString() << endl;
			cout << ":::" << gameinfo.getPlayer(2).getAction().toStdString() << endl;
			cout<< "après le moteur d'inférence" << endl;
		}
	}
	if(USE_COMMUNICATION_XML)
	{
		//response = DataNetworkRepresentation::encoding(gameinfo).toStdString();
	}
	else
	{
		response =  "["+gameinfo.getPlayers()[1].getName().toStdString();
		response +="["+gameinfo.getPlayers()[1].getAction().toStdString()+"]";
		response += "["+PokerTool::intToString(gameinfo.getPlayer(1).getMise())+"]]";
	}
	
	cout << "message reponse : " << response << endl;
	size_t si = strlen(response.c_str());

	size_t ret = write(sockfd, response.c_str(), si );

	return ret;
}

int func(string port,string name)
{

	int sockfd;
	int connfd;
	int bind_return;
	int listen_return;
	struct sockaddr_in serv_addr;
	struct sockaddr_in cli_addr;
	socklen_t cli_addr_len;

	/* création socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	if (sockfd == -1)
	{
		puts("SERVER: socket error");
		return 0;
	}

	/* remplit la socket serv_addr */
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(atoi(port.c_str()));

	/* relie la socket à une adresse et un port */
	bind_return = bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));

	if (bind_return == -1)
	{
		puts("SERVER: bind error");
		return 0;
	}

	/* place la socket active en socket capable de recevoir des connexions */
	listen_return = listen(sockfd, 5);

	if (listen_return == -1)
	{
		puts("SERVER: listen error");
		return 0;
	}

	cout << "Listening on port " << port << endl;

	/* boucle d'attente de connexion entrante */
	while (1)
	{
		/* récupère la taille de cli_addr */
		cli_addr_len = sizeof(cli_addr);

		cout << "------------------------------------------------" << endl;
		cout << "en attente de connexion" << endl;

		/* attend une connexion */
		if ((connfd = accept(sockfd, (struct sockaddr*) &cli_addr, &cli_addr_len)) == -1)
		{
			puts("SERVER: accept error");
			return 0;
		}
		/* Processus fils */
		if (fork() == 0)
		{
			/* fermeture socket passive */
			close(sockfd);

			/* fonction de traitement de la connexion */
			traitement_client(connfd,name);
			close(connfd); // fin de la connexion
			exit(0);
		}
		/* Processus père */
		else
		{
			/* fermeture socket connectée */
			close(connfd);
		}
			// 1 seconde de pause
			sleep(1);
	}

	//return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	if (argc != 3)
	{
		printf("Usage : < %s port> < %s name>\n", argv[1],argv[2]);
		return -1;
	}

	cout << "Joueur started..." << endl;

	func(argv[1],argv[2]);
	return a.exec();
}
